﻿#include "EditorPageAreaManagerModel.h"

#include "Window/EditorWindowGroupModel.h"
#include "Misc/Assert.h"
#include "Pages/EditorPageModel.h"
#include "PageArea/EditorPageAreaModel.h"
#include "Widgets/Splitable/EditorSplitableLayoutModel.h"

static const float HorizontalMinSize=200;
static const float HorizontalQuickMinSize=200;

static const float VerticalMinSize=100;
static const float VerticalQuickMinSize=100;

void REditorPageAreaManagerModel::FirstTimeInitializeObject()
{
    Super::FirstTimeInitializeObject();

    LayoutModel = NewObject<REditorSplitableLayoutModel>(this);
}


void REditorPageAreaManagerModel::FocusPageArea(TSharedObjectPtr<REditorPageAreaModel> InPageArea)
{
    if(FocusedPageArea == InPageArea)
    {
        return;
    }

    FocusedPageArea = InPageArea;
    NofifyCurrentPageChanged();
}

TSharedObjectPtr<REditorPageAreaModel> REditorPageAreaManagerModel::GetFocusedPageArea() const
{
    return FocusedPageArea;
}

TSharedObjectPtr<REditorPageModel> REditorPageAreaManagerModel::GetCurrentPage() const
{
    if(!FocusedPageArea)
    {
        return nullptr;
    }
    return FocusedPageArea->GetFrontPage();
}

void REditorPageAreaManagerModel::NofifyCurrentPageChanged()
{
    if(REditorWindowGroupModel::Get()->GetFocusedPageAreaManager()==this)
    {
        REditorWindowGroupModel::Get()->NotifyCurrentPageChanged();
    }
}

void REditorPageAreaManagerModel::AddPageInArea(TSharedObjectPtr<REditorPageAreaModel> InArea, TSharedObjectPtr<REditorPageModel> InPage, bool bPutInFront)
{
    GASSERT(InArea && InPage, U"参数不能为空");
    InArea->Pages.Add(InPage);
    InPage->SetOwner(InArea.Get());

    //放在最前面
    if(InArea->Pages.Num()==1 //第一个页面必然是前台页面
    || bPutInFront)
    {
        InArea->FrontPageIndex= InArea->Pages.Num()-1;
        if(InArea->IsFocusedInTree())
        {
            NofifyCurrentPageChanged();
        }
    }

    InArea->OnPageAdded.ExecuteIfBound(InPage);    
}


void REditorPageAreaManagerModel::AddPageInDefaultArea(TSharedObjectPtr<REditorPageModel> InPage, bool bPutInFront)
{
    if(!FocusedPageArea)
    {
        //create a new page area
        auto NewPageArea = NewObject<REditorPageAreaModel>(this);
        NewPageArea->Pages.Add(InPage);
        InPage->SetOwner(NewPageArea.Get());
        NewPageArea->FrontPageIndex=0;
        //这时布局树这时应当是空的
        //创建新的布局树
        auto RootNode=NewObject<REditorSplitableLayoutLeafNode>(this);
        RootNode->ItemWidgetModel=NewPageArea;
        NewPageArea->LayoutNode=RootNode;
        LayoutModel->SetLayoutTree(RootNode);

        FocusPageArea(NewPageArea);
    }
    else
    {
        AddPageInArea(FocusedPageArea,InPage,bPutInFront);
    }
}

void REditorPageAreaManagerModel::SplitToRight(TSharedObjectPtr<REditorPageAreaModel> InAreaToSplit)
{
    //找到对应的布局节点
    auto LayoutNode= InAreaToSplit->GetLayoutNode();

    //布局节点的父节点，可能为空
    TSharedObjectPtr<REditorContainerSplitableLayoutNode>
        ParentLayoutNode= LayoutNode->Parent;

    if(ParentLayoutNode&& ParentLayoutNode->IsHorizontal())
    {
        //父节点也是水平的，在父节点插入新节点即可
        auto ThisNodeIndex=ParentLayoutNode->Children.Find(LayoutNode).GetValue();
        auto NewNode=NewObject<REditorSplitableLayoutLeafNode>(this);
        auto NewArea=NewObject<REditorPageAreaModel>(this);
        NewNode->ItemWidgetModel=NewArea;
        NewArea->LayoutNode=NewNode;

        NewArea->Pages.Add(InAreaToSplit->GetFrontPage()->ShareClone(NewArea.Get()));
        NewArea->FrontPageIndex=0;

        NewNode->Parent=ParentLayoutNode;
        float TotalSize=ParentLayoutNode->SizeSum();
        float NewNodeSize=TotalSize/(ParentLayoutNode->GetChildNum());
        ParentLayoutNode->InsertNode(
            ThisNodeIndex+1,
            NewNode,
            NewNodeSize,
            HorizontalMinSize,
            HorizontalQuickMinSize
        );

        LayoutModel->SetLayoutTree(LayoutModel->GetLayoutRoot());
        
        FocusPageArea(NewArea);

        return;
    }
    else if(ParentLayoutNode)
    {
        //父节点是垂直的，需要创建一个水平节点作为父节点
        auto NewArea=NewObject<REditorPageAreaModel>(this);
        NewArea->Pages.Add(InAreaToSplit->GetFrontPage()->ShareClone(NewArea.Get()));
        NewArea->FrontPageIndex=0;
        auto NewLeafNode=NewObject<REditorSplitableLayoutLeafNode>(this);
        NewLeafNode->ItemWidgetModel=NewArea;
        NewArea->LayoutNode=NewLeafNode;

        auto NewParentNode=NewObject<REditorContainerSplitableLayoutNode>(this);
        NewParentNode->SetHorizontal();
        NewParentNode->AddChild(LayoutNode,1,HorizontalMinSize,HorizontalQuickMinSize);
        NewParentNode->AddChild(NewLeafNode,1,HorizontalMinSize,HorizontalQuickMinSize);
        auto ThisNodeIndex=ParentLayoutNode->Children.Find(LayoutNode).GetValue();
        ParentLayoutNode->Children[ThisNodeIndex]=NewParentNode;
        NewParentNode->Parent=ParentLayoutNode;

        LayoutModel->SetLayoutTree(LayoutModel->GetLayoutRoot());

        FocusPageArea(NewArea);

        return;
    }
    else
    {
        //没有父节点，这个节点就是根节点
        //需要创建一个父节点
        auto NewArea=NewObject<REditorPageAreaModel>(this);
        NewArea->Pages.Add(InAreaToSplit->GetFrontPage()->ShareClone(NewArea.Get()));
        NewArea->FrontPageIndex=0;
        auto NewLeafNode=NewObject<REditorSplitableLayoutLeafNode>(this);
        NewLeafNode->ItemWidgetModel=NewArea;
        NewArea->LayoutNode=NewLeafNode;

        auto NewParentNode=NewObject<REditorContainerSplitableLayoutNode>(this);
        NewParentNode->SetHorizontal();
        NewParentNode->AddChild(LayoutNode,1,HorizontalMinSize,HorizontalQuickMinSize);
        NewParentNode->AddChild(NewLeafNode,1,HorizontalMinSize,HorizontalQuickMinSize);

        LayoutModel->SetLayoutTree(NewParentNode);

        FocusPageArea(NewArea);

        return;

    }


}

void REditorPageAreaManagerModel::SplitToDown(TSharedObjectPtr<REditorPageAreaModel> InAreaToSplit)
{
    //找到对应的布局节点
    auto LayoutNode= InAreaToSplit->GetLayoutNode();

    //布局节点的父节点，可能为空
    TSharedObjectPtr<REditorContainerSplitableLayoutNode>
        ParentLayoutNode= LayoutNode->Parent;

    if(ParentLayoutNode&& ParentLayoutNode->IsVertical())
    {
        //父节点也是垂直的，在父节点插入新节点即可
        auto ThisNodeIndex=ParentLayoutNode->Children.Find(LayoutNode).GetValue();
        auto NewNode=NewObject<REditorSplitableLayoutLeafNode>(this);
        auto NewArea=NewObject<REditorPageAreaModel>(this);
        NewNode->ItemWidgetModel=NewArea;
        NewArea->LayoutNode=NewNode;

        NewArea->Pages.Add(InAreaToSplit->GetFrontPage()->ShareClone(NewArea.Get()));
        NewArea->FrontPageIndex=0;

        float TotalSize=ParentLayoutNode->SizeSum();
        float NewNodeSize=TotalSize/(ParentLayoutNode->GetChildNum());
        ParentLayoutNode->InsertNode(
            ThisNodeIndex+1
            ,NewNode
            ,NewNodeSize
            ,VerticalMinSize
            ,VerticalQuickMinSize
        );
        LayoutModel->SetLayoutTree(LayoutModel->GetLayoutRoot());
        
        FocusPageArea(NewArea);

        return;
    }
    else if(ParentLayoutNode)
    {
        //父节点是水平的，需要创建一个垂直节点作为父节点
        auto NewArea=NewObject<REditorPageAreaModel>(this);
        NewArea->Pages.Add(InAreaToSplit->GetFrontPage()->ShareClone(NewArea.Get()));
        NewArea->FrontPageIndex=0;
        auto NewLeafNode=NewObject<REditorSplitableLayoutLeafNode>(this);
        NewLeafNode->ItemWidgetModel=NewArea;
        NewArea->LayoutNode=NewLeafNode;

        auto NewParentNode=NewObject<REditorContainerSplitableLayoutNode>(this);
        NewParentNode->SetVertical();

        NewParentNode->AddChild(LayoutNode,1,VerticalMinSize,VerticalQuickMinSize);
        NewParentNode->AddChild(NewLeafNode,1,VerticalMinSize,VerticalQuickMinSize);
        auto ThisNodeIndex=ParentLayoutNode->Children.Find(LayoutNode).GetValue();
        ParentLayoutNode->Children[ThisNodeIndex]=NewParentNode;
        NewParentNode->Parent=ParentLayoutNode;

        LayoutModel->SetLayoutTree(LayoutModel->GetLayoutRoot());

        FocusPageArea(NewArea);

        return;
    }
    else
    {
        //没有父节点，这个节点就是根节点
        //需要创建一个父节点
        auto NewArea=NewObject<REditorPageAreaModel>(this);
        NewArea->Pages.Add(InAreaToSplit->GetFrontPage()->ShareClone(NewArea.Get()));
        NewArea->FrontPageIndex=0;
        auto NewLeafNode=NewObject<REditorSplitableLayoutLeafNode>(this);
        NewLeafNode->ItemWidgetModel=NewArea;
        NewArea->LayoutNode=NewLeafNode;

        auto NewParentNode=NewObject<REditorContainerSplitableLayoutNode>(this);
        NewParentNode->SetVertical();
        NewParentNode->AddChild(LayoutNode,1,VerticalMinSize,VerticalQuickMinSize);
        NewParentNode->AddChild(NewLeafNode,1,VerticalMinSize,VerticalQuickMinSize);

        LayoutModel->SetLayoutTree(NewParentNode);

        FocusPageArea(NewArea);

        return;
    }
}

void REditorPageAreaManagerModel::ClosePage(TSharedObjectPtr<REditorPageAreaModel> InArea, int64_t InPageIndex)
{
    GASSERT(InArea, U"参数不能为空");

    //找到对应的布局节点
    auto LayoutNode= InArea->GetLayoutNode();

    //布局节点的父节点，可能为空
    TSharedObjectPtr<REditorContainerSplitableLayoutNode>
        ParentLayoutNode= LayoutNode->Parent;

    if(InArea->Pages.Num()==1 && !ParentLayoutNode)
    {
        //一共只有这一个区域一个页面，清空所有区域
        ClearAll();
        return;
    }

    if(InArea->Pages.Num()==1
        && ParentLayoutNode->Children.Num()==2
    )
    {
        //父节点只有两个区域
        //删除该区域和父节点，使用另一个节点替换父节点

        auto ThisNodeIndex=ParentLayoutNode->Children.Find(LayoutNode).GetValue();
        auto AnotherNodeIndex=1-ThisNodeIndex;
        auto AnotherNode=ParentLayoutNode->Children[AnotherNodeIndex];
        
        if(ParentLayoutNode->Parent)
        {
            TSharedObjectPtr<REditorContainerSplitableLayoutNode>
                GrandParent=ParentLayoutNode->Parent;
            auto ParentNodeIndex=GrandParent->Children.Find(ParentLayoutNode).GetValue();
            GrandParent->Children[ParentNodeIndex]=AnotherNode;
            AnotherNode->Parent=GrandParent;

            LayoutModel->SetLayoutTree(LayoutModel->GetLayoutRoot());
        }
        else
        {
            //父节点就是根节点
            AnotherNode->Parent=nullptr;
            LayoutModel->SetLayoutTree(AnotherNode);
        }

        if(FocusedPageArea==InArea)
        {
            //在另一个节点中找一个页面区域聚焦
            FocusPageArea(FindFirstPageArea(AnotherNode));
        }
        return;
    }

    if(InArea->Pages.Num()==1)
    {
        //仅删除该节点即可
        ParentLayoutNode->RemoveChild(LayoutNode);

        LayoutModel->SetLayoutTree(LayoutModel->GetLayoutRoot());

        if(FocusedPageArea==InArea)
        {
            FocusPageArea(FindFirstPageArea(ParentLayoutNode));
        }

        return;
    }

    //仅仅是移除页面
    InArea->Pages.RemoveAt(InPageIndex);
    if(InPageIndex==InArea->FrontPageIndex)
    {
        //找一个新的页面放在前面
        if(InArea->FrontPageIndex>=InArea->Pages.Num())
        {
            InArea->FrontPageIndex=InArea->Pages.Num()-1;
        }

        if(InArea->IsFocusedInTree())
        {
            NofifyCurrentPageChanged();
        }
    }
    else if(InPageIndex<InArea->FrontPageIndex)
    {
        InArea->FrontPageIndex--;
    }

    InArea->OnPageClosed.ExecuteIfBound(InPageIndex);    

}

void REditorPageAreaManagerModel::ReplacePage(TSharedObjectPtr<REditorPageModel> Old, TSharedObjectPtr<REditorPageModel> New)
{
    TSharedObjectPtr<REditorPageAreaModel> PageArea=Old->GetOwner();
    auto Index=PageArea->Pages.Find(Old).GetValue();
    PageArea->Pages[Index]=New;

    if(PageArea->FrontPageIndex==Index
        && FocusedPageArea==PageArea)
    {
        NofifyCurrentPageChanged();
    }

    PageArea->OnPageReplaced.ExecuteIfBound(Index);
}

void REditorPageAreaManagerModel::ClearAll()
{
    LayoutModel->Clear();
    FocusPageArea(nullptr);
}

TSharedObjectPtr<REditorPageAreaModel> REditorPageAreaManagerModel::FindFirstPageArea(
    TSharedObjectPtr<REditorSplitableLayoutNode> InNode)
{
    if(InNode->IsA<REditorContainerSplitableLayoutNode>())
    {
        TSharedObjectPtr<REditorContainerSplitableLayoutNode>
            ContainerNode=InNode;
        return FindFirstPageArea(ContainerNode->Children[0]);
    }
    
    TSharedObjectPtr<REditorSplitableLayoutLeafNode>
        LeafNode=InNode;

    return LeafNode->ItemWidgetModel;
}
